package net.jxtz.jxtzos.authentication;

import lombok.extern.slf4j.Slf4j;
import net.jxtz.jxtzos.authentication.exception.IllegalAuthorizationException;
import net.jxtz.jxtzos.authentication.exception.InvalidJwtTokenException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.security.access.AccessDecisionManager;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.access.AuthorizationServiceException;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.authentication.InsufficientAuthenticationException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.FilterInvocation;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;

import java.util.Collection;
import java.util.Set;
import java.util.stream.Collectors;

/**
 *
 * 自定义资源权限校验类
 * 对过滤后的资源进行匹配处理
 * 最终资源校验
 *
 * @author a123
 */
@Slf4j
@Component
public class MyAccessDecisionManager implements AccessDecisionManager {

    @Override
    public void decide(Authentication authentication, Object o, Collection<ConfigAttribute> collection) throws AccessDeniedException, InsufficientAuthenticationException {
        log.info("进入资源匹配校验：" + authentication.getName() + " ==> " + authentication.getAuthorities());
        FilterInvocation filterInvocation = (FilterInvocation) o;
        String requestUrl = filterInvocation.getRequestUrl();
        log.info(requestUrl);
        for (String s : JwtAuthorizationFilter.WHITE_LIST) {
            if (requestUrl.contains(s)){
                log.info("白名单，请求放行");
                return;
            }
        }

        if (antPathMatcher.match("/error", requestUrl)){
            log.error("错误");
            SecurityContextHolder.clearContext();
            throw new InvalidJwtTokenException("错误，可能是jwt过期的原因");
        }else {
            // 过滤角色集合
            final Set<String> collect = collection.stream().map(ConfigAttribute::getAttribute).collect(Collectors.toSet());
            // 这是解析用户的完整角色集合
            final Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities();
            for (GrantedAuthority authority : authorities) {
                // 如果当前 Authentication 有 requestUrl 的权限, 则认证通过
                // 用antPathMatcher匹配处理
                for (String s : collect) {
                    if (antPathMatcher.match(authority.getAuthority(), s)) {
                        log.info("资源匹配成功");
                        return;
                    }
                }
            }

            // 如果所有资源都进行匹配还是没有成功的话
            // 清空所有资源
            log.error("没有合适的资源进行匹配");
            SecurityContextHolder.clearContext();
            throw new AuthorizationServiceException("权限不足");
        }
    }

    @Override
    public boolean supports(ConfigAttribute configAttribute) {
        return true;
    }

    @Override
    public boolean supports(Class<?> aClass) {
        return true;
    }



    private AntPathMatcher antPathMatcher;

    @Autowired
    public void setAntPathMatcher(AntPathMatcher antPathMatcher){
        this.antPathMatcher = antPathMatcher;
    }
}
